package org.yh.controller;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.yh.mapper.UserMapper;
import org.yh.model.User;
import org.yh.security.MyUsernameNotFoundException;
import org.yh.security.PasswordEncoderUtil;
import org.yh.util.ConstantVal;
import org.yh.util.JwtTokenUtils;
import org.yh.util.Result;
import org.yh.util.ResultEnum;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: yh
 * @Description:
 * @Date: Created in 14:45 2018/12/10
 * @Modified By:
 */
@Controller
@Slf4j
public class SecurityController {

    @Autowired
    UserMapper userMapper;

    @Autowired
    private AuthenticationManager myAuthenticationManager;

    @Autowired
    DefaultKaptcha defaultKaptcha;

    @GetMapping(value = "/login")
    public String toLogin() {
        log.info("跳转首页");
        return "view/login.html";
    }

    @GetMapping("hello/{a}")
    public String hello(@PathVariable String a) {
        return "你好：" + a;
    }

    @RequestMapping(value = "/403")
    @ResponseBody
    public Result notAuthority() {
        log.info("没有此权限");
        return Result.builder()
                .code(ResultEnum.NOAUTHORITY.getCode())
                .message(ResultEnum.NOAUTHORITY.getMsg())
                .build();
    }

    @RequestMapping(value = "/userLogin")
    @ResponseBody
    public Result userLogin(HttpServletRequest request) {
        String token;
        log.info("登录方法");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String kaptcha = request.getParameter("kaptcha");
        String s = request.getSession().getAttribute(ConstantVal.CHECK_CODE).toString();
        log.info(s);
        if (StringUtils.isEmpty(kaptcha) || !s.equals(kaptcha)) {
            log.info("验证码错误！正确验证码：" + s);
            return Result.builder()
                    .code(ResultEnum.FAIL.getCode())
                    .message("验证码错误")
                    .build();
        }

        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, password);
        try {
            //使用SpringSecurity拦截登陆请求 进行认证和授权
            Authentication authenticate = myAuthenticationManager.authenticate(usernamePasswordAuthenticationToken);
            SecurityContextHolder.getContext().setAuthentication(authenticate);
            //使用redis session共享
            HttpSession session = request.getSession();
            // 这个非常重要，否则验证后将无法登陆
            session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
        } catch (AuthenticationException e) {
            return Result.builder()
                    .code(ResultEnum.FAIL.getCode())
                    .message("用户名或者密码错误")
                    .build();
        }

        return Result.builder()
                .code(ResultEnum.SUCCESS.getCode())
                .message("登录成功")
                .build();
    }

    @RequestMapping("/captcha.jpg")
    public void applyCheckCode(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
        byte[] captchaChallengeAsJpeg = null;
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        try {
            //生产验证码字符串并保存到session中
            String createText = defaultKaptcha.createText();
            log.info("验证码为：" + createText);
            httpServletRequest.getSession().setAttribute(ConstantVal.CHECK_CODE, createText);
            //使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中
            BufferedImage challenge = defaultKaptcha.createImage(createText);
            ImageIO.write(challenge, "jpg", jpegOutputStream);
        } catch (IllegalArgumentException e) {
            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        //定义response输出类型为image/jpeg类型，使用response输出流输出图片的byte数组
        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
        httpServletResponse.setHeader("Cache-Control", "no-store");
        httpServletResponse.setHeader("Pragma", "no-cache");
        httpServletResponse.setDateHeader("Expires", 0);
        httpServletResponse.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream =
                httpServletResponse.getOutputStream();
        responseOutputStream.write(captchaChallengeAsJpeg);
        responseOutputStream.flush();
        responseOutputStream.close();
    }


    /**
     * 登录成功页面
     *
     * @return
     */
    @GetMapping("/")
    public String showHome() {
        String name = SecurityContextHolder.getContext().getAuthentication().getName();
        log.info("当前登陆用户：" + name);
        return "home.html";
    }

    @PostMapping("/register")
    @ResponseBody
    public Result register(User user) {
        String password = user.getPassword();
        password = PasswordEncoderUtil.passwordEncoder(password);
        user.setPassword(password);
        int i = userMapper.insert(user);
        if (i > 0) {
            return Result.builder()
                    .code(ResultEnum.SUCCESS.getCode())
                    .message("ok")
                    .build();
        }
        return null;
    }

    @GetMapping("testJwt")
    @ResponseBody
    public String testJwt() {
        return "认证后可访问";
    }

    @RequestMapping("/add")
    @ResponseBody
    @PreAuthorize("hasAuthority('per_add')")
    public Result printAdd(HttpServletRequest req) {
        String header = req.getHeader(JwtTokenUtils.TOKEN_HEADER);
        log.info("header值:" + header);
        return Result.builder()
                .code(ResultEnum.SUCCESS.getCode())
                .message("如果你看见这句话，说明你有per_add权限")
                .build();
    }

    @RequestMapping("/update")
    @ResponseBody
    @PreAuthorize("hasAuthority('per_update')")
    public Result printUpdate() {
        return Result.builder()
                .code(ResultEnum.SUCCESS.getCode())
                .message("如果你看见这句话，说明你有per_update权限")
                .build();
    }

    @RequestMapping("/login/error")
    @ResponseBody
    public Map<String, Object> loginError(HttpServletRequest request, HttpServletResponse response) {
        response.setContentType("text/html;charset=utf-8");
        AuthenticationException exception =
                (AuthenticationException) request.getSession().getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
        log.info("登录失败原因：" + exception);
        HashMap<String, Object> map = new HashMap<>();
        map.put("code", "error");
        map.put("msg", exception.toString());
        return map;
    }
}
